﻿// mpi_pi.cpp
//

#include <iostream>
#include <cassert>
#include <mpi.h>
#include <chrono>

int main(int argc, char** argv)
{
    const int N = 10000000;    // 区间个数
    const double dx = 1.0 / (double)N;    // 区间长度
    const int root = 0;    // 根进程

    // 初始化MPI
    MPI_Init(&argc, &argv);

    // 获取进程总数 np
    int np = 0;
    MPI_Comm_size(MPI_COMM_WORLD, &np);
   
    auto t0 = std::chrono::high_resolution_clock::now();    // 获取当前时刻

    // 获取当前进程编号 ip
    int ip = 0;
    MPI_Comm_rank(MPI_COMM_WORLD, &ip);   // ip从0开始

    assert(N % np == 0);
    // 当前进程上的区间个数
    int n = N / np;

    // 计算当前进程上的部分
    double x = (double)ip / (double)np;
    double pi_i = 0;
    for (int i = 0; i < n; i++) {
        pi_i += 4 / (1 + x * x) * dx;
        x += dx;
    }

    // 对所有进程上的pi_i 求和
    double pi = 0;
    MPI_Reduce(&pi_i, &pi, 1, MPI_DOUBLE, MPI_SUM, root , MPI_COMM_WORLD);

    auto t1 = std::chrono::high_resolution_clock::now();    // 结束时刻
    std::chrono::duration<double> t = t1 - t0;

    // 在根进程root上输出结果
    if (ip == root) {
        std::cout << "pi = " << std::scientific << pi 
                  << " , t = " << std::fixed << t.count() << "\n";
    }

    // 退出MPI环境
    MPI_Finalize();
}
